package paodekuai

import (
	"gitee.com/yuya000/cards-game-server-go/logwarp"
	"sort"
)

const (
	PaiStyleSola         = iota // 单张 0
	PaiStyleSolaPair            // 单对 1
	PaiStyleThreeWithTwo        // 三代二 2
	PaiStyleShunZi              // 顺子 3
	PaiStyleLianDui             // 连对 4
	PaiStyleSanShun             // 三顺 5
	PaiStyleFly                 // 飞机 6
	PaiStyleBomb                // 炸弹 7
	PaiStyleEmpty        = -2
	PaiStyleUnknow       = -1
)

func PaiPointText(s int) string {
	switch s {
	case PaiStyleSola:
		return "单张"
	case PaiStyleSolaPair:
		return "单对"
	case PaiStyleThreeWithTwo:
		return "三代"
	case PaiStyleShunZi:
		return "顺子"
	case PaiStyleLianDui:
		return "连对"
	case PaiStyleSanShun:
		return "三顺"
	case PaiStyleFly:
		return "飞机"
	case PaiStyleBomb:
		return "炸弹"
	case PaiStyleEmpty:
		return "要不起"
	}
	return "未知牌型"
}

var PaiValMap = map[string]int{
	`hei_3`:   100,
	`hei_4`:   200,
	`hei_5`:   300,
	`hei_6`:   400,
	`hei_7`:   500,
	`hei_8`:   600,
	`hei_9`:   700,
	`hei_10`:  800,
	`hei_11`:  900,
	`hei_12`:  1000,
	`hei_13`:  1100,
	`hong_1`:  1200,
	`hong_3`:  100,
	`hong_4`:  200,
	`hong_5`:  300,
	`hong_6`:  400,
	`hong_7`:  500,
	`hong_8`:  600,
	`hong_9`:  700,
	`hong_10`: 800,
	`hong_11`: 900,
	`hong_12`: 1000,
	`hong_13`: 1100,
	`mei_1`:   1200,
	`mei_3`:   100,
	`mei_4`:   200,
	`mei_5`:   300,
	`mei_6`:   400,
	`mei_7`:   500,
	`mei_8`:   600,
	`mei_9`:   700,
	`mei_10`:  800,
	`mei_11`:  900,
	`mei_12`:  1000,
	`mei_13`:  1100,
	`fang_1`:  1200,
	`fang_2`:  1400,
	`fang_3`:  100,
	`fang_4`:  200,
	`fang_5`:  300,
	`fang_6`:  400,
	`fang_7`:  500,
	`fang_8`:  600,
	`fang_9`:  700,
	`fang_10`: 800,
	`fang_11`: 900,
	`fang_12`: 1000,
	`fang_13`: 1100,
}

type paival []int

func (a paival) Len() int           { return len(a) }
func (a paival) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a paival) Less(i, j int) bool { return a[i] < a[j] }

type Pai struct {
	Style    int
	Point    int
	Paival   []int
	Pai      []string
	HoldPais []string
}

func (p *Pai) findSola() bool {
	logwarp.Std().Debugln("findSola()")
	if len(p.Pai) == 1 {
		p.Style = PaiStyleSola
		p.Point = p.Paival[0]
		return true
	}
	return false
}

func (p *Pai) findBomb() bool {
	repeat := findRepeat(p.Paival, 4)
	logwarp.Std().Debugln("findBomb()", repeat)
	if len(p.Pai) == 4 && len(repeat) == 1 && len(repeat[0]) == 4 { // 炸弹
		p.Style = PaiStyleBomb
		p.Point = p.Paival[0]
		return true
	}
	return false
}

func (p *Pai) findThreeWith() bool {
	repeat := findRepeat(p.Paival, 3)
	logwarp.Std().Debugln("findThreeWith()", repeat)
	if len(p.Pai) <= 5 {
		var repai []int
		for _, pai := range repeat {
			if len(pai) == 3 {
				repai = pai
			}
		}
		if len(repai) != 3 {
			return false
		}
		if len(p.HoldPais)-len(p.Pai) == 0 {
		} else if len(p.Paival)-3 != 2 {
			return false
		}
		p.Style = PaiStyleThreeWithTwo
		p.Point = repai[0]
		return true
	}
	return false
}

func (p *Pai) findSunZi() bool {
	continuous := findContinuous(p.Paival)
	logwarp.Std().Debugln("findSunZi()", continuous)
	if len(p.Pai) >= 5 && len(continuous) == 1 && len(continuous[0]) == len(p.Pai) {
		p.Style = PaiStyleShunZi
		p.Point = continuous[0][len(continuous[0])-1]
		return true
	}
	return false
}

func (p *Pai) findLianDui() bool {
	repeat := findRepeat(p.Paival, 2)
	logwarp.Std().Debugln("findLianDui()", repeat)
	if len(repeat) >= 2 {
		for _, c := range repeat {
			if len(c) != 2 {
				return false
			}
		}
		if !checkContinuous(repeat) {
			return false
		}
		if len(repeat)*2 != len(p.Pai) {
			return false
		}
		p.Style = PaiStyleLianDui
		p.Point = repeat[len(repeat)-1][0]
		return true
	}
	return false
}

func (p *Pai) findSanShun() bool {
	repeat := findRepeat(p.Paival, 3)
	logwarp.Std().Debugln("findSanShun()", repeat)
	if len(repeat) >= 2 {
		for _, c := range repeat {
			if len(c) != 3 {
				return false
			}
		}
		if !checkContinuous(repeat) {
			return false
		}
		if len(repeat)*3 != len(p.Pai) {
			return false
		}
		p.Style = PaiStyleSanShun
		p.Point = repeat[len(repeat)-1][0]
		return true
	}
	return false
}

func (p *Pai) findFly() bool {
	repeat := findRepeat(p.Paival, 3)
	logwarp.Std().Debugln("findFly()", repeat)
	if len(repeat) >= 2 {
		for _, c := range repeat {
			if len(c) != 3 {
				return false
			}
		}
		if !checkContinuous(repeat) {
			return false
		}
		if len(repeat)*2 == len(p.Pai)-len(repeat)*3 {
		} else if len(p.HoldPais)-len(p.Pai) == 0 {
		} else {
			return false
		}
		p.Style = PaiStyleFly
		p.Point = repeat[len(repeat)-1][0]
		return true
	}
	return false
}

func (p *Pai) findSolaPair() bool {
	logwarp.Std().Debugln("findSolaPair()", p.Paival)
	if len(p.Paival) == 2 {
		if p.Paival[0] == p.Paival[1] {
			p.Style = PaiStyleSolaPair
			p.Point = p.Paival[1]
			return true
		}
	}
	return false
}

func (p *Pai) findStyle() {
	// 单张
	if p.findSola() {
		return
	}
	if p.findBomb() { // 炸弹
		return
	}
	if p.findSolaPair() { // 单对
		return
	}
	if p.findSunZi() { // 顺子
		return
	}
	if p.findLianDui() { // 连对
		return
	}
	if p.findSanShun() { // 三顺
		return
	}
	if p.findFly() { // 飞机
		return
	}
	if p.findThreeWith() { // 三代
		return
	}
	p.Style = PaiStyleUnknow
	p.Point = 0
}

func NewPai(paiSlice []string, hold []string) *Pai {
	if len(paiSlice) == 0 {
		return &Pai{
			Style: PaiStyleEmpty,
		}
	}
	var paivs []int
	for _, p := range paiSlice {
		paivs = append(paivs, PaiValMap[p])
	}
	sort.Sort(paival(paivs))
	pai := &Pai{Pai: paiSlice, HoldPais: hold, Paival: paivs}
	pai.findStyle()
	return pai
}

func findRepeat(paivs []int, limit int) [][]int {
	var (
		temp   []int
		retval [][]int
	)
	for _, paiv := range paivs {
		if len(temp) == 0 {
			temp = append(temp, paiv)
		} else if temp[0] == paiv {
			temp = append(temp, paiv)
		} else if len(temp) > limit-1 {
			retval = append(retval, temp)
			temp = []int{paiv}
		} else {
			temp = []int{paiv}
		}
	}
	if len(temp) > limit-1 {
		retval = append(retval, temp)
	}
	return retval
}

func findContinuous(paivs []int) [][]int {
	var (
		temp   []int
		retval [][]int
	)
	for _, paiv := range paivs {
		if len(temp) == 0 {
			temp = append(temp, paiv)
		} else if temp[len(temp)-1]+100 == paiv {
			temp = append(temp, paiv)
		} else if len(temp) > 1 {
			retval = append(retval, temp)
			temp = []int{paiv}
		} else {
			temp = []int{paiv}
		}
	}
	if len(temp) > 1 {
		retval = append(retval, temp)
	}
	return retval
}

func checkContinuous(slc [][]int) bool {
	var slcc []int
	for _, sl := range slc {
		slcc = append(slcc, sl[0])
	}
	f := slcc[0]
	for _, sl := range slcc[1:] {
		if f+100 != sl {
			return false
		}
		f = sl
	}
	return true
}

func RemoveRepByMap(slc []int) []int {
	result := []int{}
	tempMap := map[int]byte{} // 存放不重复主键
	for _, e := range slc {
		l := len(tempMap)
		tempMap[e] = 0
		if len(tempMap) != l { // 加入map后，map长度变化，则元素不重复
			result = append(result, e)
		}
	}
	return result
}
